package com.qying.limit;


/**
 * 令牌桶算法
 * 原理:
 *     有一个令牌管理员,根据限流大小,定速往令牌桶里放令牌
 *     如果令牌数量满了,超过令牌桶容量的限制,那就丢弃
 *     系统在接受一个用户请求时,都会先去令牌桶要一个令牌
 *     如果拿到令牌,那么就处理业务逻辑
 *     如果拿不到令牌就直接拒绝请求
 *
 *     如果令牌发放的策略正确，这个系统即不会被拖垮，
 *     也能提高机器的利用率。Guava 的 RateLimiter 限流组件，
 *     就是基于令牌桶算法实现的。
 *
 */
public class TokenBLimit {

    //每秒处理数(放入令牌数量)
    private long putTokenRate;

    //最后刷新时间
    private long refreshTime;

    //令牌桶容量
    private long capacity;

    //当前桶内令牌数
    private long currentToken = 0l;

    public static void main(String[] args) {
        TokenBLimit limit = new TokenBLimit();

        for(int i = 0;i< 100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    boolean b = limit.tokenBucketTryAcquire();
                    if (b) {
                        System.out.println("111111111");
                    }else {
                        System.out.println("222222222222");
                    }
                }
            }).start();
        }
    }


    boolean tokenBucketTryAcquire() {

        //获取系统当前时间
        long currentTimeMillis = System.currentTimeMillis();

        //生成的令牌 =(当前时间-上次刷新时间)* 放入令牌的速率
        long generateToken = (currentTimeMillis - refreshTime) / 1000 * putTokenRate;

        // 当前令牌数量 = 之前的桶内令牌数量+放入的令牌数量
        currentToken = Math.min(capacity, generateToken + currentToken);

        refreshTime = currentTimeMillis;

        if (currentToken > 0) {
            currentToken --;
            return true;
        }

        return false;
    }
}
